package com.yunhe.transfer.websocket;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yunhe.common.model.authority.Station;
import com.yunhe.transfer.client.AuthorityClient;
import com.yunhe.transfer.client.MeasHistoryClient;
import com.yunhe.transfer.client.MeasRealtimeClient;
import com.yunhe.common.constant.MeasurementConsts;
import com.yunhe.common.model.DomainList;
import com.yunhe.common.model.ResultObject;
import com.yunhe.common.model.authority.StationDTO;
import com.yunhe.common.model.data.Measurement;
import com.yunhe.common.util.DateTimeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 通过webSocket方式获取数据并保存到历史量测和实时量测
 */
@Component
public class RealtimeMeasBatchSaveHandler extends TextWebSocketHandler {

    private static final Logger logger = LoggerFactory.getLogger(RealtimeMeasBatchSaveHandler.class);

    private static final ObjectMapper mapper = new ObjectMapper();

    @Autowired
    private MeasRealtimeClient measRealtimeClient;
    @Autowired
    private MeasHistoryClient measHistoryClient;
    @Autowired
    private AuthorityClient authorityClient;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) {
        String payload = message.getPayload();
        try {
            Map<String, Object> dataMap = (Map<String, Object>)mapper.readValue(payload, Map.class);
            Object listObj = dataMap.get("list");
            Object rtimeObj = dataMap.get("rtime");
            Object stationCodeObj = dataMap.get("stationCode");
            logger.info("接受实时数据");
            String timeZoneId = null;
            if (stationCodeObj != null) {
                try {
                    long stationCode = Long.parseLong(stationCodeObj.toString());
                    Station station = authorityClient.getStationById(stationCode).getResults();
                    timeZoneId = station.getTimeZone();
                } catch (Exception e) {
                    logger.error("获取电站{}时区出错", stationCodeObj, e);
                }
            }
            if (listObj != null) {
                List<Map<String, Object>> measurements = (List<Map<String, Object>>) listObj;
                if (rtimeObj == null) {
                    saveMeas(measurements, timeZoneId);
                } else {
                    saveMeas(measurements, ((Number)rtimeObj).longValue(), timeZoneId);
                }
                // TODO 用于压测返回，压测结束后可删除-------开始
                ResultObject result = new ResultObject<>(measurements.size());
                session.sendMessage(new TextMessage(mapper.writeValueAsString(result)));
                // TODO 用于压测返回，压测结束后可删除-------结束
            }
        } catch (Exception e) {
            logger.error("保存量测值出错", e);
        }
    }

    private void saveMeas(List<Map<String, Object>> mapList, String timeZoneId) {
        CompletableFuture.runAsync(() -> {
            try {
                List<Measurement> measurements = map2Meas(mapList, timeZoneId);
                save(measurements);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    private void saveMeas(List<Map<String, Object>> mapList, Long rtime, String timeZoneId) {
        CompletableFuture.runAsync(() -> {
            try {
                List<Measurement> measurements = map2Meas(mapList, timeZoneId);
                measurements.forEach(v -> {
                    v.setDtime(DateTimeUtils.getDateString(rtime, timeZoneId));
                    v.setRtime(rtime);
                });
                save(measurements);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    private void save(List<Measurement> measurements) {
        DomainList<Measurement> domainList = new DomainList<>(measurements);
        measRealtimeClient.saveObj(domainList);
        measHistoryClient.save(domainList, MeasurementConsts.FREQUENCY.Original.value());
    }

    private List<Measurement> map2Meas(List<Map<String, Object>> mapList, String timeZoneId) {
        List<Measurement> measurements = new ArrayList<>(mapList.size());
        for (Map<String, Object> map : mapList) {
            Measurement measurement = new Measurement();
            measurement.setPointNumber(Long.parseLong(map.get("pointNumber").toString()));
            measurement.setVal(((Number)map.get("val")).doubleValue());
            Object rtime = map.get("rtime");
            if (rtime != null) {
                measurement.setRtime(((Number)rtime).longValue());
                measurement.setDtime(DateTimeUtils.getDateString(((Number)rtime).longValue(), timeZoneId));
            }
            measurements.add(measurement);
        }
        return measurements;
    }
}